# This option is currently used to prevent recursion
option(CORROSION_TESTS "Enable Corrosion tests" ON)
mark_as_advanced(CORROSION_TESTS)
if(NOT CORROSION_TESTS)
    return()
endif()

option(CORROSION_TESTS_CXXBRIDGE
        "Build cxxbridge tests which requires cxxbridge executable being available"
        OFF)
option(CORROSION_TESTS_KEEP_BUILDDIRS
    "By default corrosion tests will cleanup after themselves. This option limits the cleaning up to the
     target directories and will keep the build directories, which may be useful for caching."
    OFF)
mark_as_advanced(CORROSION_TESTS_NO_CLEANUP)

set(test_install_path "${CMAKE_CURRENT_BINARY_DIR}/test-install-corrosion")
file(REAL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/.." corrosion_source_dir)
set(test_header_contents
        "option(CORROSION_TESTS_FIND_CORROSION \"Use Corrosion as a subdirectory\" OFF)"
        "if (CORROSION_TESTS_FIND_CORROSION)"
        "    set(CMAKE_PREFIX_PATH \"${test_install_path}\" CACHE INTERNAL \"\" FORCE)"
        "    find_package(Corrosion REQUIRED PATHS \"${test_install_path}\" NO_CMAKE_SYSTEM_PATH)"
        "else()"
        "    add_subdirectory(\"${corrosion_source_dir}\" corrosion)"
        "endif()"
)

string(REPLACE ";" "\n" test_header_contents "${test_header_contents}")

file(WRITE test_header.cmake "${test_header_contents}")

option(CORROSION_TESTS_INSTALL_CORROSION
        "Install Corrosion to a test directory and let tests use the installed Corrosion"
        OFF)
if(CORROSION_TESTS_INSTALL_CORROSION)
    add_test(NAME "install_corrosion_configure"
        COMMAND
            ${CMAKE_COMMAND}
            -S "${CMAKE_CURRENT_SOURCE_DIR}/.."
            -B "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion"
            -DCORROSION_VERBOSE_OUTPUT=ON
            -DCORROSION_TESTS=OFF
            -DCMAKE_BUILD_TYPE=Release
            -G${CMAKE_GENERATOR}
            "-DCMAKE_INSTALL_PREFIX=${test_install_path}"
    )
    add_test(NAME "install_corrosion_build"
            COMMAND
            ${CMAKE_COMMAND} --build "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion" --config Release
            )
    add_test(NAME "install_corrosion_install"
            COMMAND
            ${CMAKE_COMMAND} --install "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion" --config Release
        )
    set_tests_properties("install_corrosion_configure" PROPERTIES FIXTURES_SETUP "fixture_corrosion_configure")
    set_tests_properties("install_corrosion_build"     PROPERTIES FIXTURES_SETUP "fixture_corrosion_build")
    set_tests_properties("install_corrosion_build"     PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_configure")
    set_tests_properties("install_corrosion_install"   PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_build")
    set_tests_properties("install_corrosion_install"   PROPERTIES FIXTURES_SETUP "fixture_corrosion_install")

    add_test(NAME "install_corrosion_build_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build-corrosion")
    set_tests_properties("install_corrosion_build_cleanup" PROPERTIES
        FIXTURES_CLEANUP
        "fixture_corrosion_configure;fixture_corrosion_build"
    )

    add_test(NAME "install_corrosion_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${test_install_path}")
    set_tests_properties("install_corrosion_cleanup" PROPERTIES
        FIXTURES_CLEANUP
        "fixture_corrosion_configure;fixture_corrosion_build;fixture_corrosion_install"
    )
endif()

function(corrosion_tests_add_test test_name bin_names)
    set(options "IS_HOSTBUILD")
    set(one_value_kewords "TEST_SRC_DIR")
    set(multi_value_keywords "")
    cmake_parse_arguments(PARSE_ARGV 2 TST "${options}" "${one_value_kewords}" "${multi_value_keywords}")
    set(pass_through_arguments "${TST_UNPARSED_ARGUMENTS}")

# In the future we could add multiple tests here for different configurations (generator, build mode, rust version ...)
# which would allow us to simplify the github job matrix
    if(TST_TEST_SRC_DIR)
        set(test_dir "${TST_TEST_SRC_DIR}")
    else()
        set(test_dir "${test_name}")
    endif()

    set(configure_cmake_args)
    if(CMAKE_C_COMPILER)
        list(APPEND configure_cmake_args "C_COMPILER" "${CMAKE_C_COMPILER}")
    endif()
    if(CMAKE_CXX_COMPILER)
        list(APPEND configure_cmake_args "CXX_COMPILER" "${CMAKE_CXX_COMPILER}")
    endif()
    if(CMAKE_C_COMPILER_TARGET)
        list(APPEND configure_cmake_args "C_COMPILER_TARGET" "${CMAKE_C_COMPILER_TARGET}")
    endif()
    if(CMAKE_CXX_COMPILER_TARGET)
        list(APPEND configure_cmake_args "CXX_COMPILER_TARGET" "${CMAKE_CXX_COMPILER_TARGET}")
    endif()
    if(CMAKE_GENERATOR_PLATFORM)
        list(APPEND configure_cmake_args "GENERATOR_PLATFORM" "${CMAKE_GENERATOR_PLATFORM}")
    endif()
    if(CMAKE_CROSSCOMPILING)
        list(APPEND configure_cmake_args SYSTEM_NAME "${CMAKE_SYSTEM_NAME}")
    endif()
    if(CMAKE_OSX_ARCHITECTURES)
        list(APPEND configure_cmake_args OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}")
    endif()
    if(CMAKE_OSX_SYSROOT)
        list(APPEND configure_cmake_args OSX_SYSROOT "${CMAKE_OSX_SYSROOT}")
    endif()
    if(CMAKE_TOOLCHAIN_FILE)
        list(APPEND configure_cmake_args TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}")
    endif()

    add_test(NAME "${test_name}_build"
            COMMAND
            ${CMAKE_COMMAND}
            -P "${CMAKE_SOURCE_DIR}/test/ConfigureAndBuild.cmake"
            SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/${test_dir}"
            BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}"
            GENERATOR "${CMAKE_GENERATOR}"
            RUST_TOOLCHAIN "${Rust_TOOLCHAIN}"
            CARGO_TARGET "${Rust_CARGO_TARGET}"
            ${configure_cmake_args}
            ${pass_through_arguments}

            COMMAND_EXPAND_LISTS
            )
    set_tests_properties("${test_name}_build" PROPERTIES FIXTURES_SETUP "build_fixture_${test_name}")
    if(CORROSION_TESTS_INSTALL_CORROSION)
        set_tests_properties("${test_name}_build" PROPERTIES FIXTURES_REQUIRED "fixture_corrosion_install")
    endif()
    foreach(bin ${bin_names})
        if(WIN32)
            set(bin_filename "${bin}.exe")
        else()
            set(bin_filename "${bin}")
        endif()
        add_test(NAME "${test_name}_run_${bin}" COMMAND "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}/${bin_filename}")
        set_tests_properties("${test_name}_run_${bin}" PROPERTIES FIXTURES_REQUIRED "build_fixture_${test_name}")
        # CMAKE_CROSSCOMPILING is not set when cross-compiling with VS (via -A flag).
        # Todo: We could run x86 binaries on x64 hosts.
        if((CMAKE_CROSSCOMPILING OR CMAKE_VS_PLATFORM_NAME) AND NOT "${TST_IS_HOSTBUILD}")
            # Todo: In the future we could potentially run some tests with qemu.
            set_tests_properties("${test_name}_run_${bin}" PROPERTIES DISABLED TRUE)
        endif()
    endforeach()

    if(CORROSION_TESTS_KEEP_BUILDDIRS)
        add_test(NAME "${test_name}_cleanup_artifacts"
            COMMAND "${CMAKE_COMMAND}" --build "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}" --target clean
        )
        add_test(NAME "${test_name}_cleanup_cargo"
            COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}/cargo"
            )
        set_tests_properties("${test_name}_cleanup_artifacts" PROPERTIES FIXTURES_CLEANUP "build_fixture_${test_name}")
        set_tests_properties("${test_name}_cleanup_cargo" PROPERTIES FIXTURES_CLEANUP "build_fixture_${test_name}")
    else()
        add_test(NAME "${test_name}_cleanup" COMMAND "${CMAKE_COMMAND}" -E remove_directory "${CMAKE_CURRENT_BINARY_DIR}/build-${test_name}")
        set_tests_properties("${test_name}_cleanup" PROPERTIES FIXTURES_CLEANUP "build_fixture_${test_name}")
    endif()
endfunction()

# Please keep this in alphabetical order.
add_subdirectory(config_discovery)
add_subdirectory(cargo_flags)
add_subdirectory(cpp2rust)
if(Rust_VERSION VERSION_GREATER_EQUAL "1.64.0")
    # Flag `--crate-type` is only supported since Rust 1.64.0
    add_subdirectory(crate_type)
    add_subdirectory(override_crate_type)
endif()
add_subdirectory(custom_profiles)
if(NOT Rust_CROSSCOMPILING AND Rust_VERSION VERSION_GREATER_EQUAL "1.60.0")
    add_subdirectory(custom_target)
endif()
add_subdirectory(cbindgen)
add_subdirectory(corrosion_install)
add_subdirectory(cxxbridge)
add_subdirectory(envvar)
add_subdirectory(features)
add_subdirectory(find_rust)
add_subdirectory(gensource)
add_subdirectory(hostbuild)
add_subdirectory(multitarget)
add_subdirectory(nostd)
add_subdirectory("output directory")
add_subdirectory(parse_target_triple)
add_subdirectory(rust2cpp)
add_subdirectory(rustflags)
add_subdirectory(workspace)
